/**
* @file LiveViewWindow.cpp in LiveGraph
* @author linfe
* @comment
* Create on 2022/9/25 23:46
* @version 1.0
**/


#include "LiveViewWindow.h"
#include <glog/logging.h>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <iostream>
#include <qwt_plot_grid.h>
#include <qwt_legend.h>
#include <QMetaType>
#include <QwtPlotZoomer>

#define BAUD_LIST { \
9600,  19200, 57600,115200, 230400,460800,921600 };

#define X_DIV_LIST {0,1e-9,5e-7,1e-6,5e-4,1e-3,5e-1,1,10}
#define X_DIV_LIST_TEXT {"AUTO","1ns","500ns","1us","500us","1ms","500ms","1s","10s"}
#define Y_DIV_LIST {0,0.001,0.01,0.1,1,10,100,1000};
#define Y_DIV_LIST_TEXT {"AUTO","0.001","0.01","0.1","1","10","100","1000"}


LiveViewWindow::LiveViewWindow(QMainWindow *parent) : QMainWindow(parent), ui(new Ui_LiveGraphMain) {
    ui->setupUi(this);
    th_serial = nullptr;
    status = new QLabel();
    ui->statusbar->addWidget(status);
    data_pre = {0, 0};

    cur_xdiv = 0;
    cur_ydiv = 0;
    InitUi();
    qRegisterMetaType<LiveData>("LiveData");
    qRegisterMetaType<QSerialPort::SerialPortError>("QSerialPort::SerialPortError");
    timer = new QTimer();
    connect(timer, SIGNAL(timeout()), this, SLOT(on_1secTimer()));
    timer->start(1000);
}

LiveViewWindow::~LiveViewWindow() {
    delete status;
    delete ui;
    if (timer->isActive()) {
        timer->stop();
    }
    delete timer;
    if (th_serial) {
        if (th_serial->isRunning()) {
            th_serial->quit();
            th_serial->wait(100);
        }
    }
    delete th_serial;
    delete grid;
}

void LiveViewWindow::InitUi() {
    ui->cbxBaudRate->clear();
    ui->cbxXDiv->clear();
    ui->cbxYDiv->clear();
    ScanHardware();
    int baudrates[] = BAUD_LIST;
    for (const auto &b : baudrates) {
        ui->cbxBaudRate->addItem(QString::number(b));
    }
    QString x_div_list[] = X_DIV_LIST_TEXT;
    for (const auto &x : x_div_list) {
        ui->cbxXDiv->addItem(x);
    }
    QString y_div_list[] = Y_DIV_LIST_TEXT;
    for (const auto &y : y_div_list) {
        ui->cbxYDiv->addItem(y);
    }
    /*inti qwt*/
    ui->qwtPlot->setAxisAutoScale(QwtAxis::YLeft);
    QPoint point[3];
    for (int i = 0; i < 3; i++) {
/*        for (auto &d: point_data) {
            points[i] << QPointF(d.gpst, d.gb[i]);
        }*/
        if (curves[i] == nullptr)
            curves[i] = new QwtPlotCurve(titles[i]);   //设置曲线
        curves[i]->setSamples(points[i]);
        curves[i]->setPen(colors[i], 2, Qt::SolidLine);    //设置画笔(颜色,粗细,线条样式)
        curves[i]->attach(ui->qwtPlot);   //把曲线附加到qwtPlot
        curves[i]->setCurveAttribute(QwtPlotCurve::Fitted, false);   //曲线光滑
    }
    grid = new QwtPlotGrid();
    grid->setMajorPen(Qt::gray, 1, Qt::DotLine);
    grid->attach(ui->qwtPlot);
    ui->qwtPlot->axisAutoScale(QwtPlot::xBottom);
    ui->qwtPlot->axisAutoScale(QwtPlot::yLeft);
    ui->qwtPlot->setAxisTitle(QwtPlot::xBottom, "Time/s");
    ui->qwtPlot->setAxisTitle(QwtPlot::yLeft, "");
    ui->qwtPlot->replot();
    ui->qwtPlot->setAutoReplot(true);   //自动更新

//    QwtPlotZoomer *zoomer = new QwtPlotZoomer( canvas );

}

void OnImuMsg(uint8_t *buffer) {

}

void LiveViewWindow::on_btnConnect_clicked() {
    if (ports.empty()) {
        status->setText("No available device");
        return;
    }
    double xdiv_list[] = X_DIV_LIST;
    cur_xdiv = xdiv_list[ui->cbxXDiv->currentIndex()];
    double ydiv_list[] = Y_DIV_LIST;
    cur_ydiv = ydiv_list[ui->cbxYDiv->currentIndex()];

    QSerialPortInfo info = ports[ui->cbxPortName->currentIndex()];
    handler.SetInfo(info);
    int baudrates[] = BAUD_LIST;
    auto bd_idx = ui->cbxBaudRate->currentIndex();
    if (bd_idx > sizeof(baudrates)) {
        status->setText("illegal index for baud rate!");
        return;
    }
    auto baud_rate = (QSerialPort::BaudRate) baudrates[bd_idx];
    handler.SetBaudRate(baud_rate);

    if (th_serial) {
        if (handler.IsOpen()) {
            emit SerialControl(false);
        } else {
            emit SerialControl(true);
        }
        return;
    } else {
        th_serial = new QThread();
    }
    if (ports.empty()) {
        qDebug() << "No device available";
        status->setText("No device available");
        return;
    }

    handler.moveToThread(th_serial);

    QObject::connect(th_serial, &QThread::started, &handler, &SerialPortHandler::Init);
    QObject::connect(th_serial, &QThread::finished, &handler, &SerialPortHandler::Stop);
    QObject::connect(this, &LiveViewWindow::SerialControl, &handler, &SerialPortHandler::SerialAct);
    QObject::connect(&handler, &SerialPortHandler::DataReady, this, &LiveViewWindow::on_DataReady);
    QObject::connect(&handler, &SerialPortHandler::SerialStateChanged, this, &LiveViewWindow::on_SerialStateChanged);
    th_serial->start();
}

void LiveViewWindow::on_DataReady(LiveData data) {
    if (pause_flag) {
        return;
    }
    for (int i = 0; i < 3; i++) {
        points[i] << QPointF(data.timestamp, data.data[3+i]);
        if (points[i].size() > MAX_SUPPORT_POINTS) {
            points[i].pop_front();
        }
        curves[i]->setSamples(points[i]);
       // ui->qwtPlot->axisAutoScale(QwtPlot::Axis::xBottom);
    }
    ui->qwtPlot->setAxisScale(QwtPlot::xBottom, points[0].back().x() - 10 * (cur_xdiv>0?cur_xdiv:1), points[0].back().x(), cur_xdiv);
    ui->qwtPlot->replot();
    ui->qwtPlot->update();
}

void LiveViewWindow::on_SerialStateChanged(QSerialPort::SerialPortError err) {
    if (err == QSerialPort::SerialPortError::NoError) {
        auto pal = ui->btnConnect->palette();
        if (handler.IsOpen()) {
            pal.setColor(QPalette::Button, Qt::green);
        } else {
            pal.setColor(QPalette::Button, Qt::lightGray);
        }
        ui->btnConnect->setPalette(pal);
    } else {
        status->setText("Serial Error" + QString::number(err, 10));
        auto pal = ui->btnConnect->palette();
        pal.setColor(QPalette::Button, Qt::red);
        ui->btnConnect->setPalette(pal);
        handler.Stop();
    }
}

void LiveViewWindow::on_actionClear_triggered() {
    qDebug() << "action: Clear";
    for (auto &point : points) {
        point.clear();
    }
    ui->qwtPlot->replot();
}

void LiveViewWindow::on_actionPause_triggered() {
    qDebug() << "action: Pause";
    pause_flag = !pause_flag;
    if (pause_flag) {
        status->setText("Paused");
    }
}

void LiveViewWindow::on_actionStop_triggered() {
    qDebug() << "action: Stop";
    emit SerialControl(false);
}



void LiveViewWindow::ScanHardware() {
    ports = QSerialPortInfo::availablePorts();
    ui->cbxPortName->clear();
    for (auto &p : ports) {
        ui->cbxPortName->addItem(p.portName());
    }
}

void LiveViewWindow::on_1secTimer() {
    data_cnt_per_sec = data_cnt - data_cnt_pre;
    data_cnt_pre = data_cnt;
    status->setText("Rate:" + QString::number(handler.monitor.getFrameRates()) + "Hz @ " +
                    QString::number(handler.monitor.getByteRates() / 1024) + "kB/s");
}

void LiveViewWindow::on_cbxXDiv_currentIndexChanged(int index) {
    if(index < 0)
        return;
    double x_div_list[] = X_DIV_LIST;
    cur_xdiv = x_div_list[index];
    qDebug() << "X DIV:"<<cur_xdiv<<" index "<<index;
}
void LiveViewWindow::on_cbxYDiv_currentIndexChanged(int index) {
    if(index < 0)
        return;
    double y_div_list[] = Y_DIV_LIST;
    cur_ydiv = y_div_list[index];
    qDebug() << "Y DIV:"<<cur_ydiv;
}
